//
// Created by 49647 on 2022/4/10.
//

#ifndef MYHANDLER_AMESSAGE_H
#define MYHANDLER_AMESSAGE_H

#include <unordered_map>
#include <any>
#include "ALooper.h"

struct AHandler;

struct AReplyToken : public std::enable_shared_from_this<AReplyToken> {
    static std::shared_ptr<AReplyToken> Create(const std::shared_ptr<ALooper> &looper);

private:
    explicit AReplyToken(const std::shared_ptr<ALooper> &looper) : mLooper(looper) {}

    friend struct AMessage;
    friend struct ALooper;
    std::weak_ptr<ALooper> mLooper;
    std::shared_ptr<AMessage> mReply;
    bool mReplied = false;

    std::shared_ptr<ALooper> getLooper() const {
        return mLooper.lock();
    }

    // if reply is not set, returns false; otherwise, it retrieves the reply and returns true
    bool retrieveReply(std::shared_ptr<AMessage> *reply);

    // sets the reply for this token. returns OK or error
    int setReply(const std::shared_ptr<AMessage> &reply);
};


struct AMessage : public std::enable_shared_from_this<AMessage> {
    static std::shared_ptr<AMessage> Create();
    static std::shared_ptr<AMessage> Create(uint32_t what, const std::shared_ptr<AHandler> &handler);

    uint32_t what() const {
        return mWhat;
    }
    void setWhat(uint32_t what) {
        mWhat = what;
    }

    void setTargetHandler(const std::shared_ptr<AHandler> &handler);

    void clear() {
        mItems.clear();
    }

//    template<typename T>
//    void setValue(const std::string &name, const T &value) {
//        mItems[name] = std::any(value);
//    }

    template<typename T>
    void setValue(const std::string &name, T &&value) {
        mItems[name] = std::any(value);
    }

    template<typename T>
    bool getValue(const std::string &name, T *value) {
        auto it = mItems.find(name);
        if (it == mItems.end()) {
            return false;
        }
        *value = std::any_cast<T>(mItems[name]);
        return true;
    }

    bool contains(const std::string &name) const {
        return mItems.find(name) != mItems.end();
    }

    int post(int64_t delayUs = 0);

    // Posts the message to its target and waits for a response (or error)
    // before returning.
    int postAndAwaitResponse(std::shared_ptr<AMessage> *response);

    // If this returns true, the sender of this message is synchronously
    // awaiting a response and the reply token is consumed from the message
    // and stored into replyID. The reply token must be used to send the response
    // using "postReply" below.
    bool senderAwaitsResponse(std::shared_ptr<AReplyToken> *replyID);

    // Posts the message as a response to a reply token.  A reply token can
    // only be used once. Returns OK if the response could be posted; otherwise,
    // an error.
    int postReply(const std::shared_ptr<AReplyToken> &replyID);

    // Performs a deep-copy of "this", contained messages are in turn "dup'ed".
    // Warning: RefBase items, i.e. "objects" are _not_ copied but only have
    // their refcount incremented.
    std::shared_ptr<AMessage> dup() const;

    void print() const;

private:
    AMessage() = default;

    AMessage(uint32_t what, const std::shared_ptr<AHandler> &handler) : mWhat(what) {
        setTargetHandler(handler);
    }

    friend struct ALooper;
    void deliver();

private:
    uint32_t mWhat = 0;
    std::weak_ptr<AHandler> mHandler;
    std::weak_ptr<ALooper> mLooper;
    std::unordered_map<std::string, std::any> mItems;
};


#endif //MYHANDLER_AMESSAGE_H
